#ifndef DSA_H
#define DSA_H

#include <sstream>
#include <gmp.h>

#include "signature_manager.h"
#include "GMPInt.h"

struct DSA_privatekey {

    GMPInt x; // 私有密钥

    DSA_privatekey() = default;
    DSA_privatekey(const mpz_t x) : x(x) {}

    void set_by_str(const std::string& str){
        std::istringstream ss{str};
        std::string item;
        std::getline(ss, item, ',');
        mpz_set_str(x, item.c_str(), 10);
    }

    std::string to_str() const {
        char* str1 = mpz_get_str(nullptr, 10, x);
        std::string result(str1);
        free(str1);
        return result;
    }
};

struct DSA_publickey {
    GMPInt y; // 公有密钥

    DSA_publickey() = default;
    DSA_publickey(const mpz_t y) : y(y) {}


    void set_by_str(const std::string& str){
        std::istringstream ss{str};
        std::string item;
        std::getline(ss, item, ',');
        mpz_set_str(y, item.c_str(), 10);

    }

    std::string to_str() const {
        char* str1 = mpz_get_str(nullptr, 10, y);
        std::string result(str1);
        free(str1);
        return result;
    }
};

struct DSA_publicparameter {
    GMPInt p; // 素数模数
    GMPInt q; // 素数阶
    GMPInt g; // 生成元
    bool is_valid = false; // 公钥参数是否有效

    DSA_publicparameter() = default;
    DSA_publicparameter(const mpz_t p, const mpz_t q, const mpz_t g) : p(p), q(q), g(g) {}

    std::string to_str() const {
        std::string result = p.to_str();
        result += "," + q.to_str();
        result += "," + g.to_str();
        return result;
    }
    void set_by_str(const std::string& str) {
        std::istringstream ss{str};
        std::string item;
        std::getline(ss, item, ',');
        p.set_by_str(item);

        std::getline(ss, item, ','); 
        q.set_by_str(item);

        std::getline(ss, item, ','); 
        g.set_by_str(item);
        is_valid = true;
    }
};


struct DSA_signature {
    GMPInt r;
    GMPInt s;

    DSA_signature() = default;
    DSA_signature(const mpz_t r, const mpz_t s) : r(r), s(s) {}
    
    std::string to_str() const {
        std::string result = r.to_str();
        result += "," + s.to_str();
        return result;
    }
    void set_by_str(const std::string& str) {
        std::istringstream ss{str};
        std::string item;
        std::getline(ss, item, ',');
        r.set_by_str(item);

        std::getline(ss, item, ','); 
        s.set_by_str(item);
    }
};

template<int key_length>
class DSA : public SignatureAlgorithm<DSA_privatekey, DSA_publickey, DSA_publicparameter, DSA_signature> {
public:
    void generatepublicparameters(DSA_publicparameter& publicParameters) override;
    void generateKeyPair(DSA_privatekey& privateKey, DSA_publickey& publicKey, DSA_publicparameter& publicParameters) override;
    DSA_signature sign(const PlainMessage& message, const DSA_privatekey& privateKey, const DSA_publicparameter& publicParameters) override;
    bool verify(const PlainMessage& message, const DSA_publickey& public_publicKeykey, const DSA_publicparameter& publicParameters, const DSA_signature& signature) override;
};

template<int key_length>
struct DSA_type_traits{
    using algo = DSA<key_length>;
    using private_key = DSA_privatekey;
    using public_key = DSA_publickey;
    using params = DSA_publicparameter;
    using signature = DSA_signature;
};

extern template class DSA<1024>;
extern template class DSA<2048>;
extern template class DSA<3072>;

    
#endif // DSA_H